package com.jwgf.group;

import com.alibaba.fastjson.JSON;
import com.jwgf.objectbox.ObjectBox;
import com.jwgf.objectbox.SpindleParameter;
import com.jwgf.objectbox.SpindleParameter_;
import com.jwgf.smarowindingmachine_unity.logic.MachineParameterSharedPreference;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import io.objectbox.Box;

public class GroupMap {
    private static String KEY = "group_map";
    private static GroupMap instance = new GroupMap();
    private HashMap<Group, Long> groupMap = new HashMap<>();

    private GroupMap() {
        load();
    }

    public static GroupMap getInstance() {
        return instance;
    }

    /*
    1. 遍历所有分组；
    2. 从分组中删除与新分组相交的单锭；
    3. 删除后，如果分组为空，则删除分组。如果不为空，则判断分组是否为连续单锭，如果
    不连续，则删除分组,将该组分为两组，如果连续则不处理。
    4. 将新的分组插入到分组表中。
     */


    public synchronized void put(List<Integer> spindles, long id) {
        Group group = null;
        Long value;
        List<Group> removeGroups = new ArrayList<>();
        List<Group> addGroups = new ArrayList<>();
        Iterator iterator = groupMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry<Group, Long>) iterator.next();
            group = (Group) entry.getKey();
            value = (Long) entry.getValue();
            if (Collections.disjoint(group.getSpindles(), spindles)) {
                continue;
            } else {
                group.getSpindles().removeAll(spindles);
                if (group.getSpindles().isEmpty()) {
                    removeGroups.add(group);
                } else if (!isContinuous(group.getSpindles())) {
                    removeGroups.add(group);
                    ArrayList<List<Integer>> lists = splitList(group.getSpindles());
                    addGroups.add(new Group(lists.get(0), value));
                    addGroups.add(new Group(lists.get(1), value));
                }
            }
        }
        for (Group grp : removeGroups) {
            groupMap.remove(grp);
        }
        for (Group grp : addGroups) {
            groupMap.put(grp, grp.getId());
        }
        groupMap.put(new Group(spindles, id), id);
        save();
    }

    public synchronized void remove(List<Integer> spindles) {
        Group key = null;
        Iterator iterator = groupMap.entrySet().iterator();
        List<Group> removeGroups = new ArrayList<>();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry<Group, Long>) iterator.next();
            key = (Group) entry.getKey();
            key.getSpindles().removeAll(spindles);
            if (key.getSpindles().isEmpty()) {
                removeGroups.add(key);
            }
        }
        for (Group group : removeGroups) {
            groupMap.remove(group);
        }
        save();
    }

    public synchronized int getSpindleCount() {
        List<Integer> spindles = new ArrayList<>();
        Group key = null;
        Iterator iterator = groupMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry<Group, Long>) iterator.next();
            key = (Group) entry.getKey();
            spindles.addAll(key.getSpindles());
        }
        return spindles.size();
    }


    public synchronized List<Group> getGroupList() {
        List<Group> groupList = new ArrayList<>();
        Group key = null;
        Iterator iterator = groupMap.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry entry = (Map.Entry<Group, Long>) iterator.next();
            key = (Group) entry.getKey();
            groupList.add(key);
        }
        Collections.sort(groupList);
        return groupList;
    }

    public synchronized List<Integer> getGroupNosFromID(long id) {
        List<Integer> groupNos = new ArrayList<>();
        List<Group> groups = getGroupList();
        for (int i = 0; i < groups.size(); ++i) {
            if (groups.get(i).getId() == id) {
                groupNos.add(i + 1);
            }
        }
        return groupNos;
    }

    public synchronized int getGroupCount() {
        return groupMap.size();
    }

    public synchronized List<Integer> getSpindleList(int group) {
        return getGroupList().get(group - 1).getSpindles();
    }

    public synchronized int getSpindleGroupNo(int spindle) {
        List<Group> groups = getGroupList();
        for (int i = 0; i < groups.size(); ++i) {
            if (groups.get(i).getSpindles().contains(spindle)) {
                return i + 1;
            }
        }
        return -1;
    }

    public synchronized long getSpindleParameterIdFromGroup(int group) {
        List<Group> groups = getGroupList();
        return groups.get(group - 1).getId();
    }

    public synchronized long getSpindleParameterIdFromSpindle(int spindle) {
        List<Group> groups = getGroupList();
        for (int i = 0; i < groups.size(); ++i) {
            if (groups.get(i).getSpindles().contains(spindle)) {
                return groups.get(i).getId();
            }
        }
        return 0;
    }

    private boolean isContinuous(List<Integer> list) {
        return list.size() == list.get(list.size() - 1) - list.get(0) + 1;
    }

    private ArrayList<List<Integer>> splitList(List<Integer> list) {
        ArrayList<List<Integer>> result = new ArrayList<>();

        int splitIndex = 0;
        for (int i = 0; i < list.size() - 1; ++i) {
            if (list.get(i) + 1 != list.get(i + 1)) {
                splitIndex = i + 1;
                break;
            }
        }
        result.add(new ArrayList<Integer>(list.subList(0, splitIndex)));
        result.add(new ArrayList<Integer>(list.subList(splitIndex, list.size())));

        return result;
    }

    private synchronized void save() {
        if (groupMap.size() > 8) {
            load();
        } else {
            String str = JSON.toJSONString(getGroupList());
            MachineParameterSharedPreference.getInstance().setValue(KEY, str);
        }
    }

    public synchronized void load() {
        Box<SpindleParameter> box = ObjectBox.get().boxFor(SpindleParameter.class);
        if (box.count() == 0) {
            SpindleParameter defaultPara = new SpindleParameter();
            long id = box.put(defaultPara);
            int spindleCount = Integer.valueOf(MachineParameterSharedPreference.getInstance().getValue(0x29, 1));
            List<Group> groups = new ArrayList<>();
            groups.add(new Group(1, spindleCount, id));
            HashMap<Group, Long> map = new HashMap<>();
            for (Group group : groups) {
                map.put(group, group.getId());
            }
            groupMap = map;
            save();
        } else {
            String str = MachineParameterSharedPreference.getInstance().getValue(KEY, "null");
            List<Group> groups = JSON.parseArray(str, Group.class);
            HashMap<Group, Long> map = new HashMap<>();
            for (Group group : groups) {
                SpindleParameter parameter = box.get(group.getId());
                if (parameter == null) {
                    SpindleParameter defaultPara = box.query()
                            .equal(SpindleParameter_.craftName, "default").build().findFirst();
                    if (defaultPara != null) {
                        group.setId(defaultPara.id);
                    } else {
                        defaultPara = new SpindleParameter();
                        long id = box.put(defaultPara);
                        group.setId(id);
                    }
                }
                map.put(group, group.getId());
            }
            groupMap = map;
            save();
        }
    }

}
